﻿#include "FITKGraphObjectMarkBase.h"

// VTK
#include <vtkPolyData.h>
#include <vtkUnstructuredGrid.h>
#include <vtkIntArray.h>
#include <vtkAppendFilter.h>

// Graph
#include "FITKGraphCommons.h"

// Global data
#include "FITK_Kernel/FITKCore/FITKDataRepo.h"

// Data
#include "FITK_Interface/FITKInterfaceModel/FITKModelSet.h"
#include "FITK_Interface/FITKInterfaceModel/FITKMeshSurface.h"

// Data manager
#include "FITKSetSurfPolyProvider.h"

namespace Exchange
{
    FITKGraphObjectMarkBase::FITKGraphObjectMarkBase(AbaqusData::FITKDataCase* caseData, Core::FITKAbstractDataObject* markData)
        : FITKGraphObject3D(caseData, markData)
    {
        if (!markData)
        {
            return;
        }

        // Set the layer need to be rendered.
        setRenderLayer(0, 1);

        // Save the graph information.
        m_graphInfo.Type = OtherGraph;

        // Save if the bounds are fixed or dynamic.
        m_hasFixedBounds = false;
    }

    bool FITKGraphObjectMarkBase::getComponentValid(int compId)
    {
        // Check if the data exsits.
        Core::FITKAbstractDataObject* data = Core::FITKDataRepo::getInstance()->getDataByID(compId);
        if (!data)
        {
            return false;
        }

        // Check if the id is a set or surface.
        Interface::FITKModelSet* set = Core::FITKDataRepo::getInstance()->getTDataByID<Interface::FITKModelSet>(compId);
        Interface::FITKMeshSurface* surface = Core::FITKDataRepo::getInstance()->getTDataByID<Interface::FITKMeshSurface>(compId);
        if (!set && !surface)
        {
            return false;
        }

        return true;
    }

    void FITKGraphObjectMarkBase::clearModelsInfo()
    {
        // Clear model ids.
    }

    void FITKGraphObjectMarkBase::clearData()
    {
        // Clear data in sub-class.

        // Clear the model infomation.
        clearModelsInfo();
    }

    bool FITKGraphObjectMarkBase::generateComponentGridData(int compId, vtkUnstructuredGrid* ugrid, QList<int>& modelIds
        , QList<int>& subSetIds, int instanceId, bool removeNormals)
    {
        if (!ugrid)
        {
            return false;
        }

        bool isValid = false;

        // Try to get set and surface poly data for location.
        Interface::FITKModelSet* set = Core::FITKDataRepo::getInstance()->getTDataByID<Interface::FITKModelSet>(compId);
        if (set && !isValid)
        {
            generateSetData(ugrid, set, modelIds, instanceId);

            // Save the sub set ids.
            subSetIds = FITKSetSurfPolyProvider::GetCompSetSubSetIds(compId);

            isValid = true;
        }

        Interface::FITKMeshSurface* surface = Core::FITKDataRepo::getInstance()->getTDataByID<Interface::FITKMeshSurface>(compId);
        if (surface && !isValid)
        {
            vtkUnstructuredGrid* surfGridLoc = FITKSetSurfPolyProvider::getInstance()->getSurfaceGridData(compId, modelIds, instanceId);
            if (!surfGridLoc)
            {
                return false;
            }

            ugrid->DeepCopy(surfGridLoc);

            // Save the sub set ids.
            subSetIds = FITKSetSurfPolyProvider::GetSurfaceSubSetIds(compId);

            isValid = true;
        }

        // Remove the normals data.
        if (removeNormals && ugrid)
        {
            FITKGraphCommons::RemoveCellNormals(ugrid);
        }

        return isValid;
    }

    void FITKGraphObjectMarkBase::generateGraph()
    {
        // Override in sub-class.
    }

    bool FITKGraphObjectMarkBase::getCellVisibilityWithModel(vtkCell* cell, vtkIntArray* ptModelIdArray, QHash<int, bool>& modelVisibilityHash)
    {
        if (!cell)
        {
            return false;
        }

        // Get each point's visibility in the cell.
        int nPt = cell->GetNumberOfPoints();
        for (int i = 0; i < nPt; i++)
        {
            int ptId = cell->GetPointId(i);
            int modelId = ptModelIdArray->GetValue(ptId);
            bool visible = modelVisibilityHash[modelId];
            if (!visible)
            {
                return false;
            }
        }

        return true;
    }

    void FITKGraphObjectMarkBase::generateSetData(vtkUnstructuredGrid* setGrid, Interface::FITKModelSet* set, QList<int>& modelIds, int instanceId)
    {
        if (!setGrid)
        {
            return;
        }

        QList<vtkUnstructuredGrid*> setGrids;

        // Generate set's grid data.
        generateSetDataPrivate(setGrids, set, modelIds, instanceId);

        // Get append data.
        vtkSmartPointer<vtkAppendFilter> appFilter = vtkSmartPointer<vtkAppendFilter>::New();
        for (vtkUnstructuredGrid* grid : setGrids)
        {
            if (!grid)
            {
                continue;
            }

            appFilter->AddInputData(grid);
        }

        appFilter->Update();

        // Copy data.
        setGrid->DeepCopy(appFilter->GetOutput());
    }

    void FITKGraphObjectMarkBase::generateSetDataPrivate(QList<vtkUnstructuredGrid*>& setGrids, Interface::FITKModelSet* set, QList<int>& modelIds, int instanceId)
    {
        // Get the sub-set number.
        int nSubSet = set->getDataCount();
        if (nSubSet == 0)
        {
            // Get set type.
            Interface::FITKModelEnum::FITKModelSetType type = set->getModelSetType();

            // Check the set type.
            if (type != Interface::FITKModelEnum::FITKModelSetType::FMSNode &&
                type != Interface::FITKModelEnum::FITKModelSetType::FMSElem)
            {
                return;
            }

            int modelId = -1;
            int setId = set->getDataObjectID();
            vtkUnstructuredGrid* setGrid = FITKSetSurfPolyProvider::getInstance()->getSetGridData(setId, modelId, instanceId);
            if (!setGrid)
            {
                return;
            }

            // Add to data list.
            setGrids.push_back(setGrid);

            if (!modelIds.contains(modelId))
            {
                modelIds.push_back(modelId);
            }
        }
        else
        {
            // Generate sub-set poly data.
            for (int i = 0; i < nSubSet; i++)
            {
                generateSetDataPrivate(setGrids, set->getDataByIndex(i), modelIds, instanceId);
            }
        }
    }
}   // namespace Exchange